using System; using System.Text; using System.Data; using System.Xml; using System.Xml.Linq; using System.Net; using System.IO; namespace DataSyncSample { class Program { static void Main(string[] args) { Program p = new Program(); try { // This information will be delivered to you. You will also need to get your IP address for IP address authentication. Deliver the IP address that this // service will run on and we will add it to the account settings. You can use Http://spatialstream.com/samples/ShowClientIP.ashx to determine the IP // to send. string accountName = "trialaccount"; // User account string userName = "user1"; // use user name string baseReferrer = userName; // for server to server authentication we just use the userName as the base referrer string baseUrl = "http://dc1.spatialstream.com/"; // Step #1 Authenticate using trusted IP authentication and return a cookie that contains a authentication // token for subsequent requests. CookieContainer authCookie = p.Authenticate(userName, accountName, "Group1", baseUrl, baseReferrer); // Call the data sync process p.DataSyncRecs(baseUrl, "MY_FOLDER/DATASYNCSAMPLE", "ID", authCookie, baseReferrer); } catch (ApplicationException ex) { Console.WriteLine("Error Occured! Stack Trace = " + ex.StackTrace.ToString()); } catch (Exception ex) { Console.WriteLine("Critical Error Occured! Stack Trace = " + ex.StackTrace.ToString()); } } // Does all of the work public void DataSyncRecs(string baseUrl, string resourceName, string keyFieldName, CookieContainer authCookie, string baseReferrer) { // Step #2 Prepare your data for synchronize. This step is used to access the modified records and gather the data that you // would like to synchronize. For sample purposes we will use a hardcoded data table that contains records that we will // synchronize. DataTable table = GetSampleDataTable(); // Record Sequence starts at 0, Every time we create a new record the record sequence is increased by 1 Int32 recseq = 0; // Step #3 Create a new version String versionUrl = baseUrl + "version.aspx?&action=create&recseq=" + recseq++; //recordSequence HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(versionUrl); httpWebRequest.CookieContainer = authCookie; httpWebRequest.Referer = "http://" + baseReferrer + "/index.html"; WebResponse webResponse = httpWebRequest.GetResponse(); XmlDocument versionResults = new XmlDocument(); versionResults.Load(webResponse.GetResponseStream()); webResponse.Close(); String v = ""; // versionResults.Root.Attribute("versionId").Value.ToString(); if (versionResults.SelectSingleNode("Response/@versionId") != null) { v = versionResults.SelectSingleNode("Response/@versionId").Value; } else { throw new ApplicationException("Unable to get a version id."); } try { // Create DOMS to hold information that will be passed in a post request XElement transactionDom = new XElement("Request"); transactionDom.Add(new XAttribute("versionId", v)); XElement updateRecordsDom = new XElement("Update"); updateRecordsDom.Add(new XAttribute("resource", resourceName)); XElement insertRecordsDom = new XElement("Insert"); insertRecordsDom.Add(new XAttribute("resource", resourceName)); // keeps track of the data that is currently in the queue for insert or update int counter = 0; // when counter has this many records the records are posted const int chunkSize = 50; foreach (DataRow row in table.Rows) { XElement rowDom = new XElement("Row"); // Step #4 Get Geocode // This example is using GetGeocode to get the X,Y corrdinate that is used as the geometry. If your data already contains the X,Y then you can use that // instead of going through the geocode process. String geocodeUrl = baseUrl + "GetGeocode.aspx" + "?address=" + row["Street"].ToString() + "&city=" + row["City"].ToString() + "&state=" + row["State"].ToString() + "&zip=" + row["Zip"].ToString() + "&fields=*&v=latest" + "&datasource=" + "Parcels,Street_Centerline"; httpWebRequest = (HttpWebRequest)WebRequest.Create(geocodeUrl); httpWebRequest.CookieContainer = authCookie; httpWebRequest.Referer = "http://" + baseReferrer + "/index.html"; webResponse = httpWebRequest.GetResponse(); XmlDocument geocodeDocumentXML = new XmlDocument(); geocodeDocumentXML.Load(webResponse.GetResponseStream()); webResponse.Close(); if (geocodeDocumentXML.SelectSingleNode("Response/@status").Value.ToLower() != "success" && Convert.ToInt32(geocodeDocumentXML.SelectSingleNode("Response/Results/@totalRecords").Value) > 0) { // ToDo: check min score. // noResultsQueue.Add(geocodeUrl); // handle records that do not geocode. } else { XmlNode geocodeRecord = geocodeDocumentXML.SelectSingleNode("Response/Results/Data/Row"); // Step #5 Call get by key to see if the record already exists within the database. If it does we will call // Update to update the existing record. If it does not exist we will call insert for the existing record. String getByKeyUrl = baseUrl + "GetByKey.aspx" + "?keyName=" + keyFieldName + "&keyValue=" + row[keyFieldName].ToString() + "&datasource=" + resourceName; httpWebRequest = (HttpWebRequest)WebRequest.Create(getByKeyUrl); httpWebRequest.CookieContainer = authCookie; httpWebRequest.Referer = "http://" + baseReferrer + "/index.html"; webResponse = httpWebRequest.GetResponse(); XmlDocument keyDocumentXML = new XmlDocument(); keyDocumentXML.Load(webResponse.GetResponseStream()); webResponse.Close(); string action = ""; if (keyDocumentXML.SelectSingleNode("Response/@status").Value.ToLower() != "success") { // handle error } else { int recordCount = Convert.ToInt32(keyDocumentXML.SelectSingleNode("Response/Results/@totalRecords").Value); action = (recordCount == 0 ? "Insert" : "Update"); } // Step #6 Fill the attributes on each record // Add the geometry column rowDom.Add(new XAttribute("GEOMETRY", geocodeRecord.Attributes["GEOMETRY"].Value)); foreach (DataColumn column in table.Columns) { // Add each column + value rowDom.Add(new XAttribute(column.ColumnName, row[column.ColumnName].ToString())); } if (action == "Update") { XmlNode keyNode = keyDocumentXML.SelectSingleNode("Response/Results/Data/Row"); // If update we need to add a couple of session fields. rowDom.Add(new XAttribute("_SESSIONID", keyNode.Attributes["_SESSIONID"].Value)); rowDom.Add(new XAttribute("_RECSEQ", keyNode.Attributes["_RECSEQ"].Value)); rowDom.Add(new XAttribute("_CREATEDBY", keyNode.Attributes["_CREATEDBY"].Value)); updateRecordsDom.Add(rowDom); } else { // If insert we just need to add the _RECSEQ rowDom.Add(new XAttribute("_RECSEQ", recseq++)); insertRecordsDom.Add(rowDom); } // increase the counter by one counter++; if (counter >= chunkSize) { // commit chunk postTransactionChunk(baseUrl, authCookie, baseReferrer, transactionDom); // clean up xml doms that were just loaded getting ready for the next batch transactionDom = new XElement("Request"); transactionDom.Add(new XAttribute("versionId", v)); updateRecordsDom = new XElement("Update"); updateRecordsDom.Add(new XAttribute("resource", resourceName)); insertRecordsDom = new XElement("Insert"); insertRecordsDom.Add(new XAttribute("resource", resourceName)); transactionDom.Add(updateRecordsDom); transactionDom.Add(insertRecordsDom); // reset counter counter = 0; } } } // for each // publish any records still in the queue if (counter != chunkSize) { // commit chunk postTransactionChunk(baseUrl, authCookie, baseReferrer, transactionDom); // clean up xml DOMS that were just loaded getting ready for the next batch transactionDom = new XElement("Request"); transactionDom.Add(new XAttribute("versionId", v)); updateRecordsDom = new XElement("Update"); updateRecordsDom.Add(new XAttribute("resource", resourceName)); insertRecordsDom = new XElement("Insert"); insertRecordsDom.Add(new XAttribute("resource", resourceName)); transactionDom.Add(updateRecordsDom); transactionDom.Add(insertRecordsDom); // reset counter counter = 0; } // Step # 8 publish the request String publishUrl = baseUrl + "Version.aspx?action=publish&versionId=" + v; HttpWebRequest publishRequest = (HttpWebRequest)WebRequest.Create(publishUrl); publishRequest.CookieContainer = authCookie; publishRequest.Referer = "http://" + baseReferrer + "/index.html"; WebResponse publishResponse = publishRequest.GetResponse(); publishResponse.Close(); } catch (Exception ex) { // Step # 9 roll back version on error. String publishUrl = baseUrl + "Version.aspx?action=publish&versionId=" + v; HttpWebRequest publishRequest = (HttpWebRequest)WebRequest.Create(publishUrl); publishRequest.CookieContainer = authCookie; publishRequest.Referer = "http://" + baseReferrer + "/index.html"; WebResponse publishResponse = publishRequest.GetResponse(); publishResponse.Close(); } } /// <summary> /// Used for this sample to generate data to load. In a real example this is the portion where data is extracted from your /// data store for synchronization to a layer within your DMP account. /// </summary> /// <returns></returns> DataTable GetSampleDataTable() { // // Here we create a DataTable with four columns. // DataTable table = new DataTable(); table.Columns.Add("ID", typeof(int)); table.Columns.Add("Modified_Date", typeof(DateTime)); table.Columns.Add("Street", typeof(string)); table.Columns.Add("City", typeof(string)); table.Columns.Add("State", typeof(string)); table.Columns.Add("Zip", typeof(string)); table.Columns.Add("Project_Name", typeof(string)); table.Columns.Add("Project_Type", typeof(string)); // // Here we add five DataRows. // table.Rows.Add(4, DateTime.Now, "25482 Buckwood", "Lake Forest", "CA", "", "First Build", "New"); table.Rows.Add(2, DateTime.Now, "5531 AMADOR AVE", "Westminster", "CA", "", "Amador Ave Project", "Add On"); table.Rows.Add(3, DateTime.Now, "13401 AMARILLO DR", "Westminster", "CA", "", "Amarillo Ave Project", "New"); table.Rows.Add(4, DateTime.Now, "5581 ALFRED AVE", "Westminster", "CA", "", "Alfred Ave Project", "Add On"); table.Rows.Add(5, DateTime.Now, "14651 ALLEN ST", "Westminster", "CA", "", "Allen Ave Project", "New"); return table; } /// <summary> /// Used to post a transaction chunk to the database. /// </summary> /// <param name="baseUrl">base url to the SpatialStream service</param> /// <param name="authCookie">Authentication cookie</param> /// <param name="baseReferrer">Used for authentication</param> /// <param name="transactionDom">Dom that contains the data to post</param> public void postTransactionChunk(string baseUrl, CookieContainer authCookie, string baseReferrer, XElement transactionDom) { // Step #7 commit the request by using a POST command. // Note that we are preparing all of the requests in a single post. If you are synchronizing a lot of data // you will need to move this into the loop and do it in 50 record chunks. HttpWebRequest transactionRequest = (HttpWebRequest)WebRequest.Create(baseUrl + "Transaction.aspx"); transactionRequest.CookieContainer = authCookie; transactionRequest.Referer = "http://" + baseReferrer + "/index.html"; transactionRequest.Method = "POST"; String postData = "&xml=" + transactionDom.ToString(); byte[] byteArray = Encoding.UTF8.GetBytes(postData); transactionRequest.ContentType = "application/x-www-form-urlencoded"; transactionRequest.ContentLength = byteArray.Length; Stream dataStream = transactionRequest.GetRequestStream(); dataStream.Write(byteArray, 0, byteArray.Length); dataStream.Close(); WebResponse response = transactionRequest.GetResponse(); response.Close(); } /// <summary> /// Authenticate to your DMP Account /// </summary> /// <param name="login">User name</param> /// <param name="account">Your account name</param> /// <param name="group">Group use "Group1" if you are unsure</param> /// <param name="baseUrl">Base URL for the SpatialStream service</param> /// <param name="baseReferrer">Used for authentication</param> /// <returns></returns> private CookieContainer Authenticate(string login, string account, string group, string baseUrl, string baseReferrer) { CookieContainer cookies = new CookieContainer(); // create request string sLoginRequest = baseUrl + "/admin/getSIK.aspx?ACCOUNT=" + account + "&LOGIN=" + login + "&baseReferrer=" + baseReferrer; HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(sLoginRequest); HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse(); XmlDocument responseXML = new XmlDocument(); responseXML.Load(httpResponse.GetResponseStream()); // check for fail XmlNodeList resNodes = responseXML.SelectNodes("/Response/Error/@message"); if (resNodes.Count != 0) { throw new ApplicationException("Error authenticating to service! Error=" + resNodes[0].InnerText); } // check for success resNodes = responseXML.SelectNodes("/Response/Success/@message"); String SIK = ""; if (resNodes.Count == 1) { SIK = resNodes[0].InnerText; } // used in request to make sure we are not using the cache Random random = new Random(); string[] parts = SIK.Split('/'); string url = "http://" + parts[1] + ".spatialstream.com/" + parts[2] + "/InitSession.aspx?sik=" + parts[2] + "/" + parts[3] + "&output=xml&_=" + random.Next(1000); httpRequest = (HttpWebRequest)WebRequest.Create(url); httpRequest.Method = "GET"; httpRequest.ContentType = "application/x-www-form-urlencoded"; httpRequest.CookieContainer = cookies; HttpWebResponse webResponse = (HttpWebResponse)httpRequest.GetResponse(); StreamReader responseStream = new StreamReader(webResponse.GetResponseStream()); string requestResponse = responseStream.ReadToEnd(); // Set new cookies XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(requestResponse); if (xmlDoc.SelectSingleNode("//Response[@status = 'success']") == null) { throw new ApplicationException("Error in InitSesssion"); } webResponse.Close(); responseStream.Close(); return cookies; } } }